package models

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"sort"
	"time"
)

// CouponStackingEngine 优惠券叠加引擎
type CouponStackingEngine struct {
	Rules []StackingRule
}

// StackingRule 叠加规则
type StackingRule struct {
	Type          string   `json:"type"` // mutually_exclusive, stackable, conditional
	Priority      int      `json:"priority"`
	Conditions    []string `json:"conditions"`
	Limitations   []string `json:"limitations"`
	MaxStack      int      `json:"max_stack"`
	StackingOrder []string `json:"stacking_order"`
	Description   string   `json:"description"`
}

// CouponCombination 优惠券组合
type CouponCombination struct {
	Coupons       []*Coupon `json:"coupons"`
	TotalDiscount float64   `json:"total_discount"`
	AppliedRules  []string  `json:"applied_rules"`
	Valid         bool      `json:"valid"`
	Reason        string    `json:"reason"`
}

// StackingRequest 叠加计算请求
type StackingRequest struct {
	MemberID      int64             `json:"member_id"`
	MemberLevel   int               `json:"member_level"`
	OriginalPrice float64           `json:"original_price"`
	StoreID       int64             `json:"store_id"`
	VenueID       int64             `json:"venue_id"`
	BookingDate   string            `json:"booking_date"`
	Coupons       []*Coupon         `json:"coupons"`
	GroupBuy      *GroupBuyActivity `json:"group_buy,omitempty"`
}

// StackingResponse 叠加计算响应
type StackingResponse struct {
	FinalPrice     float64         `json:"final_price"`
	TotalDiscount  float64         `json:"total_discount"`
	AppliedCoupons []AppliedCoupon `json:"applied_coupons"`
	AppliedRules   []string        `json:"applied_rules"`
	Warnings       []string        `json:"warnings"`
	Valid          bool            `json:"valid"`
	Reason         string          `json:"reason"`
}

// AppliedCoupon 应用的优惠券
type AppliedCoupon struct {
	CouponID   int64   `json:"coupon_id"`
	CouponName string  `json:"coupon_name"`
	Type       string  `json:"type"`
	Value      float64 `json:"value"`
	Discount   float64 `json:"discount"`
	Priority   int     `json:"priority"`
	Order      int     `json:"order"`
}

// NewCouponStackingEngine 创建新的优惠券叠加引擎
func NewCouponStackingEngine() *CouponStackingEngine {
	return &CouponStackingEngine{
		Rules: loadStackingRules(),
	}
}

// CalculateStacking 计算优惠券叠加
func (cse *CouponStackingEngine) CalculateStacking(req *StackingRequest) (*StackingResponse, error) {
	response := &StackingResponse{
		AppliedCoupons: []AppliedCoupon{},
		AppliedRules:   []string{},
		Warnings:       []string{},
		Valid:          true,
	}

	// 验证输入
	if err := cse.validateRequest(req); err != nil {
		response.Valid = false
		response.Reason = err.Error()
		return response, err
	}

	// 构建优惠券列表
	allCoupons := cse.buildCouponList(req)

	// 过滤有效优惠券
	validCoupons := cse.filterValidCoupons(allCoupons, req)

	// 按业务规则排序
	sortedCoupons := cse.sortCouponsByRules(validCoupons)

	// 应用叠加规则
	finalPrice, appliedCoupons, err := cse.applyStackingRules(req.OriginalPrice, sortedCoupons, req)
	if err != nil {
		response.Valid = false
		response.Reason = err.Error()
		return response, err
	}

	response.FinalPrice = finalPrice
	response.TotalDiscount = req.OriginalPrice - finalPrice
	response.AppliedCoupons = appliedCoupons
	response.AppliedRules = cse.getAppliedRules(appliedCoupons)

	return response, nil
}

// validateRequest 验证请求参数
func (cse *CouponStackingEngine) validateRequest(req *StackingRequest) error {
	if req.OriginalPrice <= 0 {
		return errors.New("原价必须大于0")
	}

	if len(req.Coupons) == 0 && req.GroupBuy == nil {
		return errors.New("至少需要提供一种优惠方式")
	}

	return nil
}

// buildCouponList 构建优惠券列表
func (cse *CouponStackingEngine) buildCouponList(req *StackingRequest) []*Coupon {
	var coupons []*Coupon

	// 添加优惠券
	coupons = append(coupons, req.Coupons...)

	// 添加团购券
	if req.GroupBuy != nil {
		groupBuyCoupon := &Coupon{
			Name:  req.GroupBuy.Name,
			Type:  1, // 现金券
			Value: req.GroupBuy.GroupPrice,
			Code:  fmt.Sprintf("GROUPBUY_%d", req.GroupBuy.Id),
		}
		coupons = append(coupons, groupBuyCoupon)
	}

	return coupons
}

// filterValidCoupons 过滤有效优惠券
func (cse *CouponStackingEngine) filterValidCoupons(coupons []*Coupon, req *StackingRequest) []*Coupon {
	var validCoupons []*Coupon
	now := time.Now().Unix()

	for _, coupon := range coupons {
		// 检查优惠券状态
		if coupon.Status != 1 {
			continue
		}

		// 检查有效期
		if coupon.StartTime > 0 && coupon.StartTime > now {
			continue
		}

		if coupon.EndTime > 0 && coupon.EndTime < now {
			continue
		}

		// 检查适用范围
		if !cse.checkCouponApplicability(coupon, req) {
			continue
		}

		validCoupons = append(validCoupons, coupon)
	}

	return validCoupons
}

// checkCouponApplicability 检查优惠券适用性
func (cse *CouponStackingEngine) checkCouponApplicability(coupon *Coupon, req *StackingRequest) bool {
	switch coupon.ApplicableType {
	case 1: // 指定门店
		if !cse.containsID(coupon.ApplicableIds, req.StoreID) {
			return false
		}
	case 2: // 指定包厢
		if !cse.containsID(coupon.ApplicableIds, req.VenueID) {
			return false
		}
	}

	// 检查最低消费
	if coupon.MinConsume > 0 && req.OriginalPrice < coupon.MinConsume {
		return false
	}

	return true
}

// containsID 检查ID是否在列表中
func (cse *CouponStackingEngine) containsID(ids string, targetID int64) bool {
	if ids == "" {
		return true
	}

	var idList []int64
	if err := json.Unmarshal([]byte(ids), &idList); err != nil {
		return true
	}

	for _, id := range idList {
		if id == targetID {
			return true
		}
	}

	return false
}

// sortCouponsByRules 按业务规则排序优惠券
func (cse *CouponStackingEngine) sortCouponsByRules(coupons []*Coupon) []*Coupon {
	// 创建排序切片
	sorted := make([]*Coupon, len(coupons))
	copy(sorted, coupons)

	// 按优先级排序
	sort.Slice(sorted, func(i, j int) bool {
		return cse.getCouponPriority(sorted[i]) < cse.getCouponPriority(sorted[j])
	})

	return sorted
}

// getCouponPriority 获取优惠券优先级
func (cse *CouponStackingEngine) getCouponPriority(coupon *Coupon) int {
	// 根据优惠券类型设置优先级
	// 优先级：团购券 > 优惠券 > 会员折扣

	switch {
	case coupon.Code != "" && len(coupon.Code) > 8 && coupon.Code[:8] == "GROUPBUY":
		return 1 // 团购券优先级最高
	case coupon.Type == 2: // 满减券
		return 2
	case coupon.Type == 1: // 现金券
		return 3
	case coupon.Type == 0: // 折扣券
		return 4
	default:
		return 5
	}
}

// applyStackingRules 应用叠加规则
func (cse *CouponStackingEngine) applyStackingRules(originalPrice float64, coupons []*Coupon, req *StackingRequest) (float64, []AppliedCoupon, error) {
	finalPrice := originalPrice
	appliedCoupons := []AppliedCoupon{}

	// 检查是否允许叠加
	if !cse.canStackCoupons(coupons) {
		return finalPrice, appliedCoupons, errors.New("优惠券不能叠加使用")
	}

	// 应用会员折扣
	if req.MemberLevel > 0 {
		memberDiscount := cse.calculateMemberDiscount(finalPrice, req.MemberLevel)
		finalPrice -= memberDiscount

		appliedCoupons = append(appliedCoupons, AppliedCoupon{
			CouponID:   0,
			CouponName: fmt.Sprintf("会员%d级折扣", req.MemberLevel),
			Type:       "member_discount",
			Value:      float64(req.MemberLevel),
			Discount:   memberDiscount,
			Priority:   99,
			Order:      0,
		})
	}

	// 按顺序应用优惠券
	for i, coupon := range coupons {
		if finalPrice <= 0 {
			break
		}

		discount := cse.calculateCouponDiscount(coupon, finalPrice)
		finalPrice -= discount

		appliedCoupons = append(appliedCoupons, AppliedCoupon{
			CouponID:   coupon.Id,
			CouponName: coupon.Name,
			Type:       cse.getCouponTypeName(coupon.Type),
			Value:      coupon.Value,
			Discount:   discount,
			Priority:   cse.getCouponPriority(coupon),
			Order:      i + 1,
		})
	}

	return math.Max(0, finalPrice), appliedCoupons, nil
}

// canStackCoupons 检查是否允许叠加
func (cse *CouponStackingEngine) canStackCoupons(coupons []*Coupon) bool {
	// 业务规则：团购券不能与优惠券叠加
	groupBuyCount := 0
	couponCount := 0

	for _, coupon := range coupons {
		if coupon.Code != "" && len(coupon.Code) > 8 && coupon.Code[:8] == "GROUPBUY" {
			groupBuyCount++
		} else {
			couponCount++
		}
	}

	// 如果同时存在团购券和其他优惠券，不允许叠加
	if groupBuyCount > 0 && couponCount > 0 {
		return false
	}

	// 检查优惠券数量限制
	if couponCount > 1 {
		return false
	}

	return true
}

// calculateMemberDiscount 计算会员折扣
func (cse *CouponStackingEngine) calculateMemberDiscount(price float64, memberLevel int) float64 {
	discountRate := 0.0

	switch memberLevel {
	case 1: // 普通会员
		discountRate = 0.05 // 5%
	case 2: // 白银会员
		discountRate = 0.10 // 10%
	case 3: // 黄金会员
		discountRate = 0.15 // 15%
	case 4: // 钻石会员
		discountRate = 0.20 // 20%
	}

	return price * discountRate
}

// calculateCouponDiscount 计算优惠券折扣
func (cse *CouponStackingEngine) calculateCouponDiscount(coupon *Coupon, currentPrice float64) float64 {
	switch coupon.Type {
	case 0: // 折扣券
		return currentPrice * (1 - coupon.Discount)
	case 1: // 现金券
		return math.Min(coupon.Value, currentPrice)
	case 2: // 满减券
		if currentPrice >= coupon.MinConsume {
			return math.Min(coupon.Value, currentPrice)
		}
	case 3: // 时长券
		return 0 // 时长券在预约时长计算中处理
	case 4: // 免费券
		return currentPrice
	case 5: // 赠品券
		return 0 // 赠品券不直接折扣
	case 6: // 特价券
		return currentPrice - coupon.Value
	}

	return 0
}

// getCouponTypeName 获取优惠券类型名称
func (cse *CouponStackingEngine) getCouponTypeName(couponType int8) string {
	typeNames := map[int8]string{
		0: "折扣券",
		1: "现金券",
		2: "满减券",
		3: "时长券",
		4: "免费券",
		5: "赠品券",
		6: "特价券",
	}

	if name, exists := typeNames[couponType]; exists {
		return name
	}

	return "未知类型"
}

// getAppliedRules 获取应用的规则
func (cse *CouponStackingEngine) getAppliedRules(appliedCoupons []AppliedCoupon) []string {
	var rules []string

	for _, coupon := range appliedCoupons {
		rules = append(rules, fmt.Sprintf("%s: ¥%.2f", coupon.CouponName, coupon.Discount))
	}

	return rules
}

// loadStackingRules 加载叠加规则
func loadStackingRules() []StackingRule {
	return []StackingRule{
		{
			Type:        "mutually_exclusive",
			Priority:    1,
			Conditions:  []string{"group_buy_and_coupon"},
			Limitations: []string{"团购券不能与优惠券同时使用"},
			MaxStack:    1,
			Description: "团购券与优惠券互斥规则",
		},
		{
			Type:        "stackable",
			Priority:    2,
			Conditions:  []string{"member_discount_and_coupon"},
			Limitations: []string{"会员折扣可与优惠券叠加"},
			MaxStack:    2,
			Description: "会员折扣与优惠券可叠加",
		},
		{
			Type:        "conditional",
			Priority:    3,
			Conditions:  []string{"price_threshold"},
			Limitations: []string{"满减券需满足最低消费"},
			MaxStack:    1,
			Description: "满减券条件规则",
		},
	}
}

// ValidateCouponCombination 验证优惠券组合
func (cse *CouponStackingEngine) ValidateCouponCombination(req *StackingRequest) (*CouponCombination, error) {
	response := &CouponCombination{
		Coupons:       req.Coupons,
		TotalDiscount: 0,
		AppliedRules:  []string{},
		Valid:         true,
	}

	// 检查互斥规则
	if err := cse.checkMutualExclusion(req); err != nil {
		response.Valid = false
		response.Reason = err.Error()
		return response, err
	}

	// 检查数量限制
	if err := cse.checkQuantityLimits(req); err != nil {
		response.Valid = false
		response.Reason = err.Error()
		return response, err
	}

	return response, nil
}

// checkMutualExclusion 检查互斥规则
func (cse *CouponStackingEngine) checkMutualExclusion(req *StackingRequest) error {
	groupBuyCount := 0
	couponCount := 0

	if req.GroupBuy != nil {
		groupBuyCount = 1
	}

	couponCount = len(req.Coupons)

	// 团购券与优惠券不能同时使用
	if groupBuyCount > 0 && couponCount > 0 {
		return errors.New("团购券与优惠券不能同时使用")
	}

	// 优惠券数量限制
	if couponCount > 1 {
		return errors.New("每次只能使用一张优惠券")
	}

	return nil
}

// checkQuantityLimits 检查数量限制
func (cse *CouponStackingEngine) checkQuantityLimits(req *StackingRequest) error {
	// 检查每人限领数量
	for _, coupon := range req.Coupons {
		if coupon.PerLimit <= 0 {
			continue
		}

		// 这里可以查询数据库检查用户已领取数量
		// 简化处理：假设已通过业务逻辑验证
	}

	return nil
}
